/*
 * @Description: 代码是生成
 * @Author: DHL
 * @Date: 2021-12-25 11:59:24
 * @LastEditors: DHL
 * @LastEditTime: 2023-01-09 13:28:18
 */
import { ElMessage } from 'element-plus'
import { cloneDeep, assign, filter, includes, merge } from 'lodash-es'
import { defineComponent, reactive, ref, onMounted, nextTick } from 'vue'
import { CodeGenModel } from '/@/api/systemTools/model/codeGenModel'
import {
  apiCodeGenGetById,
  apiCodeGenSave,
  apiCodeGenSearchColumns,
  apiCodeGenSearchDataDicKey,
  apiCodeGenSearchProjectList,
  apiCodeGenSearchResourceTree,
  apiCodeGenSearchTables,
  apiCodeGenUpdateById
} from '/@/api/systemTools/codeGen'
import {
  componentType,
  queryWay,
  getJavaTypeSelect,
  getJavaInfo,
  getClassName,
  menuListToTree
} from './utils/codeGenUtils'
import { arrayFilter, arraySerialize, getTreeParentName } from '/@/utils/twUtils'
import { useRoute } from 'vue-router'
import { stringUtils } from '/@/utils/stringUtils'
import { log } from '/@/utils/log'
import systemToolsCodeGenPreview from './preview.vue'

export default defineComponent({
  name: 'SystemToolsCodeGenForm',
  components: { systemToolsCodeGenPreview },
  emits: ['refreshTableData'],
  setup(props, { emit, expose }) {
    //////////////////////////////////////////////////
    // 属性
    //////////////////////////////////////////////////
    const dbFormRef = ref()
    const tableRef = ref()
    const resourceTreeRef = ref()
    const previewCodeRef = ref()
    const loading = ref(true)
    const route = useRoute()
    let codeGenInfo: any = {}

    /**
     * 表单操作标记
     */
    const action = ref('add')

    const state = reactive({
      tableSearchForm: {
        queryLikeStr: ''
      },
      javaType: getJavaTypeSelect(),
      queryWay: queryWay,
      componentType: componentType,
      tableData: [],
      columnData: [],
      dataDic: [] as any,
      projectList: [] as any,
      resourceList: [] as any,
      resourceTree: [] as any,
      treeFilterText: '' as any,
      activeTabsName: 'tableTab'
    })

    //////////////////////////////////////////////////
    // 生命周期
    //////////////////////////////////////////////////
    onMounted(() => {
      nextTick(async () => {
        assign(dbForm, cloneDeep(defaultForm))

        handleGetById()

        handleSearchDataDic()
        handleSearchProjectList()
      })
      loading.value = false
    })

    //////////////////////////////////////////////////
    // 表单
    //////////////////////////////////////////////////

    const defaultForm = {
      id: '', // 主键
      name: '', // 名称
      className: '', // 类名
      tableName: '', // 表名
      tableComment: '', // 表描述
      packageName: 'com.twb', // 包名
      viewPath: 'views/', // 前端页面路径
      delPrefix: '', // 删除前缀
      genName: '', // 功能描述
      genAuthor: '', // 生成人
      genType: '', // 生成类型（1：压缩包；2：物理路径）
      projectId: '', // 所属项目ID
      resourceId: '', // 父级菜单ID
      resourceName: '', // 父级资源名称
      datasourceCode: '', // 数据源编码
      optionsJson: {}, // 其他配置
      remark: '' // 备注
    }

    let dbForm = reactive<CodeGenModel>(cloneDeep(defaultForm))

    /**
     * 其他配置
     */
    const optionsJson = reactive({
      tables: [] as any, // 勾选的表
      columns: [] as any // 列配置
    })

    /**
     * 重复javaField
     */
    let repeatJavaField: Array<string> = []

    //////////////////////////////////////////////////
    // 表单验证规则
    //////////////////////////////////////////////////

    /**
     * 表单验证规则
     */
    const rules = reactive({
      className: [
        {
          required: true,
          message: '请输入类名',
          trigger: 'blur'
        }
      ],
      packageName: [
        {
          required: true,
          message: '请输入包名',
          trigger: 'blur'
        }
      ],
      viewPath: [
        {
          required: true,
          message: '请输入前端页面路径',
          trigger: 'blur'
        }
      ],
      genAuthor: [
        {
          required: true,
          message: '请输入作者',
          trigger: 'blur'
        }
      ],
      projectId: [
        {
          required: true,
          message: '请选择所属项目',
          trigger: 'blur'
        }
      ],
      resourceName: [
        {
          required: true,
          message: '请选择父级菜单',
          trigger: 'blur'
        }
      ],
      genName: [
        {
          required: true,
          message: '请输入功能描述',
          trigger: 'blur'
        }
      ]
    })

    //////////////////////////////////////////////////
    // 函数
    //////////////////////////////////////////////////

    /**
     * 查询所有表、视图
     */
    function handleSearchTables() {
      apiCodeGenSearchTables(state.tableSearchForm.queryLikeStr).then((result) => {
        if (result?.success) {
          state.tableData = result.data

          nextTick(() => {
            if (codeGenInfo.optionsJson) {
              const tableNameSelected = arraySerialize(codeGenInfo.optionsJson.tables, 'tableName')
              state.tableData.forEach((item: { tableName: unknown }) => {
                if (tableNameSelected.includes(item.tableName)) {
                  tableRef.value!.toggleRowSelection(item, undefined)
                }
              })
            }
          })
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * 查询勾选表的列
     */
    function handleTablesSelectionChange(val: any[]) {
      nextTick(() => {
        const tableNames: Array<string> = []
        optionsJson.tables = []
        val.forEach((item: any) => {
          tableNames.push(item.tableName)
          optionsJson.tables.push({
            tableName: item.tableName,
            tableComment: item.tableComment
          })
          Object.assign(dbForm, {
            tableName: item.tableName,
            tableComment: item.tableComment,
            genName: item.tableComment
          })
        })

        handleChangeClassName()

        if (tableNames && tableNames.length > 0) {
          apiCodeGenSearchColumns(tableNames.join(',')).then((result) => {
            if (result?.success) {
              state.columnData = result.data

              getJavaInfo(state.columnData)

              if (codeGenInfo.optionsJson) {
                merge(state.columnData, codeGenInfo.optionsJson.columns)
              }

              getRepeatJavaField()
            } else {
              ElMessage.error(result?.message)
            }
          })
        }
      })
    }

    /**
     * 获取className值
     */
    function handleChangeClassName() {
      dbForm.className = getClassName(
        arraySerialize(optionsJson.tables, 'tableName'),
        dbForm.delPrefix
      )
    }

    /**
     * 获取重复javaField
     * @param columnData
     */
    function getRepeatJavaField() {
      let _repeatJavaField: Array<string> = []
      arraySerialize(state.columnData, 'javaField').forEach((item: any) => {
        _repeatJavaField.push(item.toLocaleLowerCase())
      })

      repeatJavaField = filter(_repeatJavaField, (value, index, iteratee) =>
        includes(iteratee, value, index + 1)
      ) as Array<string>

      state.columnData.forEach((item: any) => {
        item.repeatJavaField = false
        if (item.javaField && repeatJavaField.includes(item.javaField.toLocaleLowerCase())) {
          item.repeatJavaField = true
        }
      })
    }

    /**
     * 查询数据字典
     */
    function handleSearchDataDic() {
      apiCodeGenSearchDataDicKey().then((result) => {
        if (result?.success) {
          state.dataDic = result.data
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * 数据字典改变事件
     */
    function handleDataDicChange(row: any) {
      getJavaInfo(state.columnData, row.columnName)
    }

    /**
     * javaField改变事件
     */
    function handleJavaFieldChange() {
      getRepeatJavaField()
    }

    /**
     * 查询项目下拉
     */
    function handleSearchProjectList() {
      apiCodeGenSearchProjectList().then((result) => {
        if (result?.success) {
          state.projectList = result.data

          handleSearchResourceTree()
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * 查询资源树
     */
    function handleSearchResourceTree() {
      apiCodeGenSearchResourceTree(dbForm.projectId).then((result) => {
        if (result?.success) {
          state.resourceList = result.data
          state.resourceTree = menuListToTree(result.data, '')

          if (stringUtils.isNotEmpty(dbForm.resourceId)) {
            const nodeList = arrayFilter(state.resourceList, 'id', dbForm.resourceId)

            if (nodeList.length > 0) {
              const resName = getTreeParentName(
                state.resourceList,
                'id',
                'pid',
                'text',
                nodeList[0]
              )

              Object.assign(dbForm, {
                resourceName: resName.join(' - ')
              })
            }
          }
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * 过滤资源树
     */
    function handleFilterResourceTreeNode(value: string, data: any) {
      if (!value) return true
      return data.label.indexOf(value) !== -1
    }

    /**
     * 监听资源树过滤
     */
    function handletReeFilterText() {
      resourceTreeRef.value!.filter(state.treeFilterText)
    }

    /**
     * 资源节点选择事件
     */
    function handleNodeClick(node: any) {
      const nodeList = arrayFilter(state.resourceList, 'id', node.id)

      const resName = getTreeParentName(state.resourceList, 'id', 'pid', 'text', nodeList[0])

      Object.assign(dbForm, {
        resourceName: resName.join(' - '),
        resourceId: node.id
      })
    }

    /**
     * 页签点击事件
     */
    function handleTabClick(tab: any, event: Event) {
      if (tab.props.name === 'previewCodeTab') {
        dbForm.optionsJson = Object.assign(optionsJson, {
          columns: state.columnData
        })
        previewCodeRef.value.createCode(dbForm)
      }
    }

    /**
     * 提交表单
     */
    function handleSubmit(isContinue: boolean) {
      dbFormRef.value.validate((valid: boolean) => {
        if (valid) {
          dbForm.optionsJson = JSON.stringify(
            Object.assign(optionsJson, {
              columns: state.columnData
            })
          )

          if (action.value === 'add') {
            addFun(isContinue)
          } else {
            editFun()
          }
        } else {
          log.warn('代码生成管理', '表单校验失败')
        }
      })
    }

    /**
     * 新增
     * @param isContinue 是否新增并继续
     */
    function addFun(isContinue: boolean) {
      apiCodeGenSave(dbForm).then((result) => {
        if (result?.success) {
          ElMessage.success(result.message)

          // handleReset(!isContinue)
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * 编辑
     * @returns
     */
    function editFun() {
      apiCodeGenUpdateById(dbForm).then((result) => {
        if (result?.success) {
          ElMessage.success(result.message)

          // handleReset(true)
        } else {
          ElMessage.error(result?.message)
        }
      })
    }

    /**
     * 重置表单
     * @param isClosed 是否关闭弹框
     */
    function handleReset(isClosed: boolean) {
      assign(dbForm, cloneDeep(defaultForm))
    }

    /**
     * 根据主键查询详情
     */
    async function handleGetById() {
      const id: string = route.query.id as string
      if (stringUtils.isNotEmpty(id)) {
        action.value = 'edit'
        await apiCodeGenGetById(id).then((result) => {
          if (result?.success) {
            codeGenInfo = result.data
            state.tableSearchForm.queryLikeStr = result.data.tableName
            merge(dbForm, result.data)
            codeGenInfo.optionsJson = JSON.parse(result.data?.optionsJson as string)

            handleSearchTables()
          }
        })
      }
    }

    /**
     * 下载ZIP
     */
    function handleDownloadZip() {
      previewCodeRef.value.handleDownloadZip()
    }

    /**
     * 下载文件
     */
    function handleDownloadFile() {
      previewCodeRef.value.handleDownloadFile()
    }

    return {
      loading,
      tableRef,
      dbFormRef,
      dbForm,
      rules,
      state,
      optionsJson,
      resourceTreeRef,
      previewCodeRef,
      handleSearchTables,
      handleTablesSelectionChange,
      handleDataDicChange,
      handleSubmit,
      handleReset,
      handleJavaFieldChange,
      handleSearchResourceTree,
      handleFilterResourceTreeNode,
      handletReeFilterText,
      handleNodeClick,
      handleTabClick,
      handleChangeClassName,
      handleDownloadZip,
      handleDownloadFile
    }
  }
})
